package com.gitee.l0km.aocache.plugin;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * RelocatingClassVisitor 类用于处理类的重定位操作。
 * 它继承自 ClassVisitor，并在类定义、方法和字段的访问中实现了包名的替换逻辑。
 * 
 * <p>
 * 该类主要功能包括：
 * </p>
 * <ul>
 * <li>重定位由 AspectJ 生成的内部类的包名。</li>
 * <li>忽略带有 @Aspect 注解的切面类。</li>
 * <li>在方法和字段中处理类型引用的重定位。</li>
 * <li>记录修改次数以便后续使用。</li>
 * </ul>
 * 
 * <p>
 * 使用示例：
 * </p>
 * 
 * <pre>
 * RelocatingClassVisitor visitor = new RelocatingClassVisitor(cv);
 * </pre>
 */
class RelocatingClassVisitor extends ClassVisitor {
	/** 原始包名 */
	private final String fromPacakge;
	/** 重定位包名 */
	private final String toPackage;
    /** 点('.')分割的原始包名 */
	private final String fromPackageD;
    /** 点('.')分割的重定位包名 */
	private final String toPackageD;
	/** 修改计数器，记录修改次数 */
	final AtomicInteger modifiedCount = new AtomicInteger();
	/** 是否忽略当前类扫描 */
	private boolean ignored;

	/**
	 * 构造方法
	 * 
	 * @param cv          目标类访问者
	 * @param fromPackage 源包名
	 * @param toPackage   目标包名
	 */
	RelocatingClassVisitor(ClassVisitor cv, String fromPackage, String toPackage) {
		super(Opcodes.ASM9, cv);
		this.fromPacakge = fromPackage;
		this.toPackage = toPackage;
		this.fromPackageD = fromPacakge.replace('/', '.');
		this.toPackageD = toPackage.replace('/', '.');
	}

	/** 处理类定义（name,signature,super,interfaces） */
	@Override
	public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
		if (null != superName && superName.startsWith(fromPacakge) && name.contains("$")) {
			/** 如果当前类是aspectj织入生成的内部类，则对类定义(signature,super,interfaces)执行重定位操作 */
			super.visit(version, access, relocate(name), relocate(signature), relocate(superName),
					relocate(interfaces));
		} else {
			super.visit(version, access, name, signature, superName, interfaces);
		}
	}

	/** 处理类注解 */
	@Override
	public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
		/** 如果当前类是有@Aspect注解的切面类，则忽略 */
		return super.visitAnnotation(descriptor, visible);
	}

	/** 处理方法中的类型引用 */
	@Override
	public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
			String[] exceptions) {
		/** 如果是切面定义类则跳过，不做重定位操作 */
		if (ignored) {
			return super.visitMethod(access, name, descriptor, signature, exceptions);
		}
		MethodVisitor mv = super.visitMethod(access, name, relocate(descriptor), relocate(signature),
				relocate(exceptions));
		return new RelocatingMethodVisitor(mv);
	}

	/** 处理字段类型引用 */
	@Override
	public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
		/** 如果是切面定义类则跳过，不做重定位操作 */
		if (ignored) {
			return super.visitField(access, name, descriptor, signature, value);
		}
		return super.visitField(access, name, relocate(descriptor), relocate(signature), value);
	}

	/** 统一包名替换逻辑 */
	private String relocate(String input) {
		if (input != null) {
			String _input = input.replace(fromPacakge, toPackage).replace(fromPackageD, toPackageD);
			if (!_input.equals(input)) {
				modifiedCount.incrementAndGet();
				return _input;
			}
		}
		return input;
	}

	private String[] relocate(String[] inputs) {
		if (inputs == null)
			return null;
		String[] results = new String[inputs.length];
		for (int i = 0; i < inputs.length; i++) {
			results[i] = relocate(inputs[i]);
		}
		return results;
	}
	private Object[] relocate(Object[] inputs) {
		if (inputs == null) {
			return null;
		}
		Object[] results = Arrays.copyOf(inputs, inputs.length);
		for (int i = 0; i < inputs.length; i++) {
			Object input = inputs[i];
			if(input instanceof String) {
				results[i] = relocate((String) input);				
			}
		}
		return results;
	}

	/** 方法内部指令的包名替换 */
	class RelocatingMethodVisitor extends MethodVisitor {
		RelocatingMethodVisitor(MethodVisitor mv) {
			super(Opcodes.ASM9, mv);
		}

		@Override
		public void visitTypeInsn(int opcode, String type) {
			super.visitTypeInsn(opcode, relocate(type));
		}

		@Override
		public void visitLdcInsn(Object value) {
			if (value instanceof String) {
                /** 如果是字符串常量，则进行重定位 */
				super.visitLdcInsn(relocate((String) value));
			} else {
				super.visitLdcInsn(value);
			}
		}

		@Override
		public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
			super.visitMethodInsn(opcode, relocate(owner), name, relocate(descriptor), isInterface);
		}

		@Override
		public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
			super.visitFieldInsn(opcode, relocate(owner), name, relocate(descriptor));
		}

		@Override
		public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
			super.visitFrame(type, numLocal, relocate(local), numStack, stack);
		}

	}
}